﻿#include "datasimuthread.h"
#include "datasimucache.h"
#include "globalstatic.h"

#include <QDebug>
#include <QDateTime>

DataSimuThread::DataSimuThread(QSettings* settings, JsonConfig* jsonConfig, QObject *parent) : QThread(parent),
    m_settings(settings),
    m_jsonConfig(jsonConfig)
{
    // 初始化
    init();
}

DataSimuThread::~DataSimuThread()
{
}

void DataSimuThread::stop()
{
    m_running = false;
}

void DataSimuThread::setChannelDescriptionList(const QList<ChannelDescription> &channelDescriptionList)
{
    m_channelDescriptionList = channelDescriptionList;
}

void DataSimuThread::setStepList(const QString &subflowName, const QList<Step> &stepList)
{
    m_subflowName = subflowName;
    m_stepList.clear();
    m_stepList << stepList;

    // 针对流程的特殊处理
}

void DataSimuThread::setStepWait(const bool &wait)
{
    m_wait = wait;
}

void DataSimuThread::assignReset(bool resetted)
{
    // 如果复位, 冻结D_时间低1, D_时间低2, D_时间低3
    //m_channelDescriptionList[1].freezed = resetted;
    //m_channelDescriptionList[33].freezed = resetted;
    //m_channelDescriptionList[65].freezed = resetted;
    for (int i = 0; i < m_channelDescriptionList.size(); i++)
        m_channelDescriptionList[i].freezed = resetted;
}

void DataSimuThread::run()
{
    // 伺服机构列表, 播放视频时使用
    m_settings->beginGroup("SystemSet");
    QStringList servoMachineList = m_settings->value("servoMachine").toStringList();
    m_settings->endGroup();
    m_videoController->setServoMachineList(servoMachineList);

    for (int i = 0; i < m_channelDescriptionList.size(); i++) {
        // 恢复所有冻结暂停的
        m_channelDescriptionList[i].freezed = false;
        // 缓存中的数据恢复默认初始值
        DataSimuCache::cacheSimuValue(m_channelDescriptionList.at(i).id, QString::number(m_channelDescriptionList.at(i).initValue));
    }
    // 时统零点
    GlobalStatic::setZeroTimeStamp(QDateTime::currentMSecsSinceEpoch());
    // 作为基准进行比较的时间
    m_baseTimeStamp = GlobalStatic::getZeroTimeStamp();
    // 正弦曲线模拟的准备
    GlobalStatic::beforeSining();

    // 启动线程
    m_running = true;
    m_wait = false;
    while (m_running) {
        // 当前时间戳
        qint64 currentTimeStamp = QDateTime::currentMSecsSinceEpoch();
        if (currentTimeStamp - m_prevTimeStamp >= m_simuInterval) {
            // 时间到, 当前时间戳作为上一次的参考
            m_prevTimeStamp = currentTimeStamp;
            //qDebug() << "*********" << QTime::currentTime().toString("HH:mm:ss");

            if (m_stepList.empty()) {
                // 发射信号通知：流程步骤完成
                emit sigSubflowFinished(m_subflowName);
                break;
            }

            qint64 timeSpan = currentTimeStamp - m_baseTimeStamp;
            if ( timeSpan > m_stepList.first().timeline ) {
                // 使用当前时间戳作为基准比较时间
                m_baseTimeStamp = currentTimeStamp;
                // 执行流程步骤
                Step step = m_stepList.takeFirst();

                // 记录并上报操作
                if (!step.code.isEmpty()) {
                    GlobalStatic::assignTrainStep(step.code);
                    emit sigStepNotify(step.code);
                }


                simuStep(step);

                // 处理故障
                handleFault(step);
            }

            // 生成仿真模拟数据
            simulating(currentTimeStamp - GlobalStatic::getZeroTimeStamp());

            // 发射信号通知: 时间间隔
            emit sigTimeReady();
        } else {
            // 线程挂起1ms
            QThread::msleep(1);
        }
    }

}

void DataSimuThread::init()
{
    // 线程运行标识
    m_running = false;
    // 仿真时间间隔: ms
    m_settings->beginGroup("Simu");
    m_simuInterval = m_settings->value("interval").toInt();
    m_settings->endGroup();

    // 把当前时间戳作为默认的上次时间
    m_prevTimeStamp = QDateTime::currentMSecsSinceEpoch();

    // 作为基准进行比较的时间
    m_baseTimeStamp = QDateTime::currentMSecsSinceEpoch();
    // 是否正在等待
    m_wait = false;

    // 流程测试名称
    m_subflowName = "";

    // 视频播放控制
    m_videoController = new VideoController(m_jsonConfig);
}

void DataSimuThread::simuStep(const Step &step)
{
    m_wait = step.wait;
    if (m_wait) {
        // 等待信号通知
        emit sigStepWait(step.name);
        waiting();
    }

    if (step.send) {
        // 发送电机指令
        emit sigSendCmd(step.name);
    }

    if (!step.video.isEmpty()) {
        // 根据伺服机构列表的数量决定播放哪段视频
        VideoPlayback playback;
        if (m_videoController->getVideoPlayback(step.video, playback)) {
            // 播放视频
            emit sigVideoPlay(playback.startTime, playback.duration);
            //qDebug() << "******" << step.video << ": " << playback.startTime << ", " << playback.duration;
        }
    }

    switch (step.id) {
    case 40000:
    case 50000:
        // 复位-复位开
        //assignReset(true);
        break;
    case 40001:
    case 50001:
        // 复位-复位关
        //assignReset(false);
        break;
    case 40201:
    case 50201:
        // 采集通道测试: 正弦曲线模拟周期是4s, 振幅是2
        GlobalStatic::setSinStart(4, 2, 3);
        break;
    case 40901:
    case 50901:
        // 极性测试: 正弦曲线模拟周期是4s, 振幅是2
        GlobalStatic::setSinStart(4, 2, 1);
        break;
    case 40213:
    case 50213:
    case 40905:
    case 50905:
        // 采集通道测试, 极性测试完成
        GlobalStatic::setSinStop();
        break;
    case 41001:
    case 42601:
        // I级位置特性: 正弦曲线模拟周期是12s, 振幅是11
        GlobalStatic::setSinStart(12, 11, 3);
        break;
    case 41013:
    case 42613:
        //  I级位置特性完成
        GlobalStatic::setSinStop();
        break;
    case 41101:
        // I级暂态特性: 正弦曲线模拟周期是12s, 振幅是8
        GlobalStatic::setSinStart(12, 8, 3, true);
        break;
    case 41113:
        // I级暂态特性完成
        GlobalStatic::setSinStop();
        break;
    case 51001:
    case 52701:
        // II级位置特性: 正弦曲线模拟周期是12s, 振幅是70
        GlobalStatic::setSinStart(12, 70, 3);
        break;
    case 51013:
    case 52713:
        //  I级位置特性完成
        GlobalStatic::setSinStop();
        break;
    case 51101:
        // II级暂态特性: 正弦曲线模拟周期是12s, 振幅是52
        GlobalStatic::setSinStart(12, 52, 3, true);
        break;
    case 51113:
        // II级暂态特性完成
        GlobalStatic::setSinStop();
        break;
    case 41201:
    case 41301:
    case 41401:
    case 41501:
    case 41601:
    case 41701:
    case 41801:
    case 41901:
    case 42001:
        // I级频率特性1度: 正弦曲线模拟周期4s, 振幅是1
        GlobalStatic::setSinStart(4, 1, 1);
        break;
    case 42101:
    case 42201:
        // I级频率特性2度: 正弦曲线模拟周期4s, 振幅是2
        GlobalStatic::setSinStart(4, 2, 1);
        break;
    case 41205:
    case 41305:
    case 41405:
    case 41505:
    case 41605:
    case 41705:
    case 41805:
    case 41905:
    case 42005:
    case 42105:
    case 42205:
        // I级频率特性1度, 2度完成
        GlobalStatic::setSinStop();
        break;
    case 42701:
    case 42801:
    case 42901:
        // I级指令故障11度：周期是12s, 振幅是11
        GlobalStatic::setSinStart(12, 11, 1);
        break;
    case 42705:
    case 42805:
    case 42905:
        // I级指令故障11度完成
        GlobalStatic::setSinStop();
        break;

    case 51201:
    case 51301:
    case 51401:
    case 51501:
    case 51601:
    case 51701:
    case 51801:
    case 51901:
    case 52001:
        // II级频率特性2度: 正弦曲线模拟周期4s, 振幅是2
        GlobalStatic::setSinStart(4, 2, 1);
        break;
    case 52101:
    case 52201:
    case 52301:
        // II级频率特性4度: 正弦曲线模拟周期4s, 振幅是4
        GlobalStatic::setSinStart(4, 4, 1);
        break;
    case 51205:
    case 51305:
    case 51405:
    case 51505:
    case 51605:
    case 51705:
    case 51805:
    case 51905:
    case 52005:
    case 52105:
    case 52205:
    case 52305:
        // II级频率特性2度, 4度完成
        GlobalStatic::setSinStop();
        break;

    case 52801:
    case 52901:
    case 53001:
        // II级指令故障70：周期是12s, 振幅是70
        GlobalStatic::setSinStart(12, 70, 1);
        break;
    case 52805:
    case 52905:
    case 53005:
        // II级指令故障70度完成
        GlobalStatic::setSinStop();
        break;
    default:
        break;
    }

    if (step.id == 42905 || step.id == 53005) {
        // 测试流程结束
        emit sigCompleteFinished();
    }
}

void DataSimuThread::handleFault(const Step &step)
{
    if (step.id == 40200) {
        if (GlobalStatic::faultCount() > 0 && GlobalStatic::containFaultCode("C15101010041")) {
            // 模拟采集通道故障
            emit sigFaultOccurred("C15101010041");
            m_wait = true;
            waiting();
        }
    }
    if (step.id == 50200) {
        if (GlobalStatic::faultCount() > 0 && GlobalStatic::containFaultCode("C15102010041")) {
            // 模拟采集通道故障
            emit sigFaultOccurred("C15102010041");
            m_wait = true;
            waiting();
        }
    }

    if (step.id == 42700) {
        if (GlobalStatic::faultCount() > 0 && GlobalStatic::containFaultCode("C15101030051")) {
            // 模拟指令故障
            emit sigFaultOccurred("C15101030051");
            m_wait = true;
            waiting();
        }
    }

    if (step.id == 52800) {
        if (GlobalStatic::faultCount() > 0 && GlobalStatic::containFaultCode("C15102030051")) {
            // 模拟指令故障
            emit sigFaultOccurred("C15102030051");
            m_wait = true;
            waiting();
        }
    }
}

void DataSimuThread::waiting()
{
    while (m_wait) {
        // 延时10ms
        QThread::msleep(10);
        // 上次计时时间和基准时间在等待期间都取当前时间戳
        m_prevTimeStamp = m_baseTimeStamp = QDateTime::currentMSecsSinceEpoch();
    }
}

void DataSimuThread::simulating(const qint64 &timeStamp)
{
    QVariantList valueList;
    for (int i = 0; i < m_channelDescriptionList.size(); i++) {
        ChannelDescription channelDescription = m_channelDescriptionList.at(i);
        // 冻结暂停仿真的数据
        if (channelDescription.freezed) {
            valueList << DataSimuCache::getSimuValue(channelDescription.id);
            continue;
        }

        // 简单工厂模式产生模拟数据
        AbstractSimuValue* simuValue = m_simuFactory.produceSimuValue(channelDescription);
        if (simuValue != nullptr) {
            QString value = simuValue->produce();
            // 缓存模拟数据
            DataSimuCache::cacheSimuValue(channelDescription.id, value);
            // 待存储的数据
            valueList << value;

            delete simuValue;
            simuValue = nullptr;
        }
    }

    // 通知存储线程进行数据存盘
    emit sigStorage(timeStamp, valueList);

}

